View Javadoc
1   package org.apache.maven.surefire.junitcore;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.surefire.common.junit4.Notifier;
23  import org.apache.maven.surefire.junitcore.pc.ParallelComputer;
24  import org.apache.maven.surefire.junitcore.pc.ParallelComputerBuilder;
25  import org.apache.maven.surefire.report.ConsoleLogger;
26  import org.apache.maven.surefire.testset.TestSetFailedException;
27  import org.apache.maven.surefire.util.TestsToRun;
28  import org.junit.Ignore;
29  import org.junit.runner.Computer;
30  import org.junit.runner.Description;
31  import org.junit.runner.Request;
32  import org.junit.runner.Result;
33  import org.junit.runner.manipulation.Filter;
34  import org.junit.runner.notification.RunListener;
35  import org.junit.runner.notification.StoppedByUserException;
36  
37  import java.util.Collection;
38  import java.util.Collections;
39  import java.util.Queue;
40  
41  import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createDescription;
42  import static org.apache.maven.surefire.common.junit4.JUnit4Reflector.createIgnored;
43  import static org.apache.maven.surefire.common.junit4.JUnit4RunListener.rethrowAnyTestMechanismFailures;
44  
45  /**
46   * Encapsulates access to JUnitCore
47   *
48   * @author Kristian Rosenvold
49   */
50  final class JUnitCoreWrapper
51  {
52      private final Notifier notifier;
53      private final JUnitCoreParameters jUnitCoreParameters;
54      private final ConsoleLogger logger;
55      private final boolean failFast;
56  
57      JUnitCoreWrapper( Notifier notifier, JUnitCoreParameters jUnitCoreParameters, ConsoleLogger logger,
58                        boolean failFast )
59      {
60          this.notifier = notifier;
61          this.jUnitCoreParameters = jUnitCoreParameters;
62          this.logger = logger;
63          this.failFast = failFast;
64      }
65  
66      void execute( TestsToRun testsToRun, Filter filter )
67          throws TestSetFailedException
68      {
69          execute( testsToRun, Collections.<RunListener>emptyList(), filter );
70      }
71  
72      void execute( TestsToRun testsToRun, Collection<RunListener> listeners, Filter filter )
73          throws TestSetFailedException
74      {
75          if ( testsToRun.allowEagerReading() )
76          {
77              executeEager( testsToRun, filter, listeners );
78          }
79          else
80          {
81              executeLazy( testsToRun, filter, listeners );
82          }
83      }
84  
85      private JUnitCore createJUnitCore( final Notifier notifier, Collection<RunListener> listeners )
86      {
87          JUnitCore junitCore = new JUnitCore();
88  
89          // custom listeners added last
90          notifier.addListeners( listeners );
91  
92          return junitCore;
93      }
94  
95      private void executeEager( TestsToRun testsToRun, Filter filter, Collection<RunListener> listeners )
96          throws TestSetFailedException
97      {
98          JUnitCore junitCore = createJUnitCore( notifier, listeners );
99          Class<?>[] tests = testsToRun.getLocatedClasses();
100         Computer computer = createComputer();
101         createRequestAndRun( filter, computer, junitCore.withReportedTests( tests ), tests );
102     }
103 
104     private void executeLazy( TestsToRun testsToRun, Filter filter, Collection<RunListener> listeners )
105         throws TestSetFailedException
106     {
107         JUnitCore junitCore = createJUnitCore( notifier, listeners );
108         // in order to support LazyTestsToRun, the iterator must be used
109         for ( Class<?> clazz : testsToRun )
110         {
111             Computer computer = createComputer();
112             createRequestAndRun( filter, computer, junitCore.withReportedTests( clazz ), clazz );
113         }
114     }
115 
116     private void createRequestAndRun( Filter filter, Computer computer, JUnitCore junitCore, Class<?>... classesToRun )
117         throws TestSetFailedException
118     {
119         Request req = Request.classes( computer, classesToRun );
120         if ( filter != null )
121         {
122             req = new FilteringRequest( req, filter );
123             if ( req.getRunner() == null )
124             {
125                 // nothing to run
126                 return;
127             }
128         }
129 
130         Result run = junitCore.run( req.getRunner() );
131         rethrowAnyTestMechanismFailures( run );
132 
133         if ( computer instanceof ParallelComputer )
134         {
135             String timeoutMessage = ( (ParallelComputer) computer ).describeElapsedTimeout();
136             if ( timeoutMessage.length() != 0 )
137             {
138                 throw new TestSetFailedException( timeoutMessage );
139             }
140         }
141     }
142 
143     private Computer createComputer()
144     {
145         return jUnitCoreParameters.isNoThreading()
146             ? Computer.serial()
147             : new ParallelComputerBuilder( logger, jUnitCoreParameters ).buildComputer();
148     }
149 
150     private final class JUnitCore
151         extends org.apache.maven.surefire.junitcore.JUnitCore
152     {
153         private final JUnit47FailFastListener failFastListener;
154 
155         JUnitCore()
156         {
157             super( notifier );
158             failFastListener = failFast ? new JUnit47FailFastListener( notifier ) : null;
159             if ( failFastListener != null )
160             {
161                 notifier.addListener( failFastListener );
162             }
163         }
164 
165         JUnitCore withReportedTests( Class<?>... tests )
166         {
167             Queue<String> stoppedTests = getRemainingTestClasses();
168             if ( stoppedTests != null )
169             {
170                 for ( Class<?> test : tests )
171                 {
172                     stoppedTests.add( test.getName() );
173                 }
174             }
175             return this;
176         }
177 
178         @Override
179         @SuppressWarnings( "checkstyle:innerassignment" )
180         protected void afterException( Throwable e )
181             throws TestSetFailedException
182         {
183             if ( failFast && e instanceof StoppedByUserException )
184             {
185                 Queue<String> stoppedTests = getRemainingTestClasses();
186                 if ( stoppedTests != null )
187                 {
188                     String reason = e.getClass().getName();
189                     Ignore reasonForSkippedTest = createIgnored( reason );
190                     for ( String clazz; ( clazz = stoppedTests.poll() ) != null; )
191                     {
192                         Description skippedTest = createDescription( clazz, reasonForSkippedTest );
193                         notifier.fireTestIgnored( skippedTest );
194                     }
195                 }
196             }
197             else
198             {
199                 super.afterException( e );
200             }
201         }
202 
203         @Override
204         protected void afterFinished()
205         {
206             Queue<String> stoppedTests = getRemainingTestClasses();
207             if ( stoppedTests != null )
208             {
209                 stoppedTests.clear();
210             }
211         }
212 
213         private Queue<String> getRemainingTestClasses()
214         {
215             return failFastListener == null ? null : failFastListener.getRemainingTestClasses();
216         }
217     }
218 }